import os
import json
import uuid
from datetime import datetime
from pathlib import Path
from flask import Flask, render_template, request, jsonify, redirect, url_for, flash, send_from_directory, Response
from werkzeug.utils import secure_filename
from PIL import Image, ImageDraw, ImageFont
import requests
from io import BytesIO

from config import Config
from database import template_dao, region_dao, project_dao
from image_processor import ImageProcessor

app = Flask(__name__)
app.config.from_object(Config)

# 禁用页面缓存
@app.after_request
def after_request(response):
    """禁用所有页面缓存"""
    # 对HTML页面禁用缓存
    if response.content_type and 'text/html' in response.content_type:
        response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
        response.headers['Pragma'] = 'no-cache'
        response.headers['Expires'] = '0'
    return response

# 初始化配置
Config.init_app()

def allowed_file(filename, allowed_extensions):
    """检查文件扩展名是否被允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in allowed_extensions

@app.route('/')
def index():
    """主页"""
    templates = template_dao.get_all_templates()
    projects = project_dao.get_all_projects()
    return render_template('index.html', templates=templates, projects=projects)

# =============================================================================
# 底板裁片管理路由
# =============================================================================

@app.route('/templates')
def templates():
    """底板裁片管理页面"""
    templates = template_dao.get_all_templates()
    
    # 转换Row对象为字典
    templates_list = [dict(tmpl) for tmpl in templates] if templates else []
    
    return render_template('templates.html', templates=templates_list)

@app.route('/templates/create', methods=['GET', 'POST'])
def create_template():
    """创建底板裁片"""
    if request.method == 'POST':
        # 检查是否有文件上传
        if 'template_image' in request.files:
            return handle_template_upload()
        
        # 处理JSON数据
        data = request.get_json()
        
        name = data.get('name')
        width = data.get('width')
        height = data.get('height')
        description = data.get('description', '')
        
        if not all([name, width, height]):
            return jsonify({'error': '请填写所有必需字段'}), 400
        
        try:
            template_id = template_dao.create_template(name, int(width), int(height), description)
            return jsonify({'success': True, 'template_id': template_id})
        except Exception as e:
            return jsonify({'error': str(e)}), 500
    
    return render_template('template_form.html', mode='create')

@app.route('/upload_template_image', methods=['POST'])
def handle_template_upload():
    """处理底板图片上传 - 支持大文件"""
    if 'template_image' not in request.files:
        return jsonify({'error': '没有选择文件'}), 400
    
    file = request.files['template_image']
    if file.filename == '':
        return jsonify({'error': '没有选择文件'}), 400
    
    print(f"上传文件名: {file.filename}")
    print(f"允许的扩展名: {app.config['ALLOWED_IMAGE_EXTENSIONS']}")
    
    if file and allowed_file(file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
        print(f"文件格式验证通过: {file.filename}")
        try:
            # 安全的文件名
            filename = secure_filename(file.filename)
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"{timestamp}_{filename}"
            file_path = app.config['UPLOAD_FOLDER'] / filename
            
            print(f"开始保存文件: {filename}")
            # 获取实际文件大小
            file.seek(0, 2)  # 移动到文件末尾
            file_size = file.tell()
            file.seek(0)  # 重置到文件开头
            print(f"文件大小: {file_size} bytes ({file_size / 1024 / 1024:.2f} MB)")
            
            # 保存文件 - 对大文件使用流式保存
            file.save(file_path)
            print(f"文件保存完成: {file_path}")
            
            # 根据文件类型获取图片尺寸
            file_extension = file_path.suffix.lower()
            try:
                if file_extension == '.psd':
                    # PSD文件处理
                    try:
                        from psd_tools import PSDImage
                        psd = PSDImage.open(file_path)
                        width, height = psd.width, psd.height
                        print(f"PSD文件尺寸: {width} x {height}")
                        
                        # 为PSD文件创建预览图（合成所有图层）
                        if width > 1200 or height > 1200:
                            composite_img = psd.composite()
                            # 转换为RGB模式
                            if composite_img.mode in ['RGBA', 'LA']:
                                rgb_img = Image.new('RGB', composite_img.size, (255, 255, 255))
                                if composite_img.mode == 'RGBA':
                                    rgb_img.paste(composite_img, mask=composite_img.split()[-1])
                                else:
                                    rgb_img.paste(composite_img)
                                composite_img = rgb_img
                            elif composite_img.mode not in ['RGB', 'L']:
                                composite_img = composite_img.convert('RGB')
                            
                            # 创建缩略图
                            thumbnail_filename = f"thumb_{filename}".replace('.psd', '.jpg')
                            thumbnail_path = app.config['UPLOAD_FOLDER'] / thumbnail_filename
                            composite_img.thumbnail((800, 800), Image.Resampling.LANCZOS)
                            composite_img.save(thumbnail_path, 'JPEG', optimize=True, quality=85)
                            print(f"已创建PSD缩略图: {thumbnail_filename}")
                    except ImportError:
                        print("警告：psd-tools未安装，无法获取PSD文件准确尺寸")
                        width, height = 3000, 2000  # PSD文件的合理默认尺寸
                    except Exception as psd_error:
                        print(f"PSD文件处理错误: {psd_error}")
                        width, height = 3000, 2000  # PSD文件的合理默认尺寸
                else:
                    # 其他格式使用PIL处理
                    with Image.open(file_path) as img:
                        width, height = img.size
                        print(f"图片尺寸: {width} x {height}")
                        
                        # 如果是大图片，创建缩略图用于预览
                        if width > 2000 or height > 2000:
                            thumbnail_filename = f"thumb_{filename}"
                            thumbnail_path = app.config['UPLOAD_FOLDER'] / thumbnail_filename
                            
                            # 创建缩略图
                            img_copy = img.copy()
                            img_copy.thumbnail((800, 800), Image.Resampling.LANCZOS)
                            img_copy.save(thumbnail_path, optimize=True, quality=85)
                            print(f"已创建缩略图: {thumbnail_filename}")
                        
            except Exception as img_error:
                print(f"图片处理错误: {img_error}")
                # 根据文件类型设置合理的默认尺寸
                if file_extension == '.psd':
                    width, height = 3000, 2000  # PSD文件的合理默认尺寸
                else:
                    width, height = 1000, 1000  # 其他格式的默认尺寸
            
            # 从表单数据获取其他信息
            name = request.form.get('name', f"底板_{timestamp}")
            description = request.form.get('description', '')
            
            print(f"创建底板记录: {name}")
            
            # 创建底板记录
            template_id = template_dao.create_template(
                name=name,
                width=width,
                height=height,
                description=description,
                image_path=str(filename),
                original_filename=file.filename
            )
            
            print(f"底板创建成功，ID: {template_id}")
            
            return jsonify({
                'success': True,
                'template_id': template_id,
                'width': width,
                'height': height,
                'image_path': filename,
                'file_size': file_size
            })
            
        except Exception as e:
            print(f"上传处理错误: {e}")
            return jsonify({'error': f'文件处理失败: {str(e)}'}), 500
    
    print(f"文件格式验证失败: {file.filename}")
    return jsonify({'error': f'不支持的文件格式。当前文件: {file.filename}，支持的格式: {", ".join(app.config["ALLOWED_IMAGE_EXTENSIONS"])}'}), 400

@app.route('/load_from_path', methods=['POST'])
def load_from_path():
    """从本地路径加载图片信息"""
    data = request.get_json()
    image_path = data.get('image_path', '').strip()
    
    if not image_path:
        return jsonify({'error': '请输入图片路径'}), 400
    
    try:
        from pathlib import Path
        file_path = Path(image_path)
        
        if not file_path.exists():
            return jsonify({'error': '文件不存在'}), 400
        
        if not file_path.is_file():
            return jsonify({'error': '路径不是文件'}), 400
        
        # 检查文件扩展名
        allowed_extensions = app.config['ALLOWED_IMAGE_EXTENSIONS']
        if file_path.suffix.lower().lstrip('.') not in allowed_extensions:
            return jsonify({'error': '不支持的文件格式'}), 400
        
        # 根据文件类型获取尺寸信息
        if file_path.suffix.lower() == '.psd':
            # PSD文件处理
            try:
                from psd_tools import PSDImage
                psd = PSDImage.open(file_path)
                width, height = psd.width, psd.height
                print(f"PSD文件尺寸: {width} x {height}")
            except ImportError:
                return jsonify({'error': 'PSD文件需要安装psd-tools库'}), 400
            except Exception as e:
                return jsonify({'error': f'读取PSD文件失败: {str(e)}'}), 500
        else:
            # 其他格式使用PIL
            try:
                with Image.open(file_path) as img:
                    width, height = img.size
            except Exception as e:
                return jsonify({'error': f'读取图片文件失败: {str(e)}'}), 500
        
        # 获取文件大小
        file_size = file_path.stat().st_size
        
        return jsonify({
            'success': True,
            'width': width,
            'height': height,
            'file_size': file_size,
            'filename': file_path.name
        })
        
    except Exception as e:
        return jsonify({'error': f'读取文件失败: {str(e)}'}), 500

@app.route('/create_template_from_path', methods=['POST'])
def create_template_from_path():
    """从本地路径创建底板"""
    data = request.get_json()
    
    name = data.get('name', '').strip()
    image_path = data.get('image_path', '').strip()
    description = data.get('description', '').strip()
    
    if not all([name, image_path]):
        return jsonify({'error': '请填写底板名称和图片路径'}), 400
    
    try:
        from pathlib import Path
        file_path = Path(image_path)
        
        if not file_path.exists():
            return jsonify({'error': '文件不存在'}), 400
        
        # 根据文件类型获取尺寸
        if file_path.suffix.lower() == '.psd':
            # PSD文件处理
            try:
                from psd_tools import PSDImage
                psd = PSDImage.open(file_path)
                width, height = psd.width, psd.height
                print(f"创建PSD底板: {width} x {height}")
            except ImportError:
                return jsonify({'error': 'PSD文件需要安装psd-tools库'}), 400
            except Exception as e:
                return jsonify({'error': f'读取PSD文件失败: {str(e)}'}), 500
        else:
            # 其他格式使用PIL
            try:
                with Image.open(file_path) as img:
                    width, height = img.size
            except Exception as e:
                return jsonify({'error': f'读取图片文件失败: {str(e)}'}), 500
        
        # 创建底板记录（存储原始路径）
        template_id = template_dao.create_template(
            name=name,
            width=width,
            height=height,
            description=description,
            image_path=str(file_path),  # 存储完整路径
            original_filename=file_path.name
        )
        
        return jsonify({
            'success': True,
            'template_id': template_id,
            'width': width,
            'height': height
        })
        
    except Exception as e:
        return jsonify({'error': f'创建底板失败: {str(e)}'}), 500

@app.route('/test_upload')
def test_upload():
    """测试上传功能页面"""
    return render_template('test_upload.html')

@app.route('/test_customize')
def test_customize():
    """测试定制编辑器页面"""
    return render_template('test_customize.html')

@app.route('/test_image/<int:template_id>')
def test_image_direct(template_id):
    """直接测试图片加载"""
    template = template_dao.get_template_by_id(template_id)
    if not template:
        return f"模板{template_id}不存在"
    
    template_dict = dict(template)
    image_path = template_dict.get('image_path')
    if not image_path:
        return f"模板{template_id}没有图片路径"
    
    from pathlib import Path
    file_path = Path(image_path) if Path(image_path).is_absolute() else app.config['UPLOAD_FOLDER'] / image_path
    
    return f"""
    <h1>图片测试 - 模板ID: {template_id}</h1>
    <p><strong>模板名称:</strong> {template_dict['name']}</p>
    <p><strong>图片路径:</strong> {image_path}</p>
    <p><strong>实际路径:</strong> {file_path}</p>
    <p><strong>文件存在:</strong> {file_path.exists()}</p>
    <p><strong>文件大小:</strong> {file_path.stat().st_size / 1024 / 1024:.2f} MB</p>
    <p><strong>模板尺寸:</strong> {template_dict['width']} x {template_dict['height']}</p>
    
    <h2>图片显示测试:</h2>
    <img src="/template_image/{template_id}" style="max-width: 500px; border: 1px solid #ccc;" 
         onload="console.log('图片加载成功');"
         onerror="console.error('图片加载失败'); this.style.display='none'; this.nextElementSibling.style.display='block';">
    <div style="display: none; padding: 20px; background: #f0f0f0; border: 1px solid #ccc;">
        图片加载失败
    </div>
    
    <h2>直接链接:</h2>
    <a href="/template_image/{template_id}" target="_blank">在新窗口中打开图片</a>
    
    <h2>在定制编辑器中测试:</h2>
    <a href="/intelligent?template_id={template_id}">使用此底板进行智能定制</a>
    """

@app.route('/templates/<int:template_id>')
def view_template(template_id):
    """查看底板裁片详情"""
    template = template_dao.get_template_by_id(template_id)
    if not template:
        flash('底板裁片不存在', 'error')
        return redirect(url_for('templates'))
    
    regions = region_dao.get_regions_by_template(template_id)
    
    # 转换Row对象为字典，使其可以JSON序列化
    template_dict = dict(template) if template else {}
    regions_list = [dict(region) for region in regions] if regions else []
    
    return render_template('template_detail.html', 
                         template=template_dict, 
                         regions=regions_list)

@app.route('/templates/<int:template_id>/edit', methods=['GET', 'POST'])
def edit_template(template_id):
    """编辑底板裁片"""
    template = template_dao.get_template_by_id(template_id)
    if not template:
        return jsonify({'error': '底板裁片不存在'}), 404
    
    if request.method == 'POST':
        data = request.get_json()
        
        name = data.get('name')
        width = data.get('width')
        height = data.get('height')
        description = data.get('description', '')
        
        if not all([name, width, height]):
            return jsonify({'error': '请填写所有必需字段'}), 400
        
        try:
            template_dao.update_template(template_id, name, int(width), int(height), description)
            return jsonify({'success': True})
        except Exception as e:
            return jsonify({'error': str(e)}), 500
    
    return render_template('template_form.html', mode='edit', template=template)

@app.route('/templates/<int:template_id>/delete', methods=['POST'])
def delete_template(template_id):
    """删除底板裁片"""
    try:
        template_dao.delete_template(template_id)
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# =============================================================================
# 定制区域管理路由
# =============================================================================

@app.route('/templates/<int:template_id>/regions/create', methods=['POST'])
def create_region(template_id):
    """为底板创建定制区域"""
    data = request.get_json()
    
    name = data.get('name')
    x = data.get('x')
    y = data.get('y')
    width = data.get('width')
    height = data.get('height')
    
    if not all([name, x is not None, y is not None, width, height]):
        return jsonify({'error': '请填写所有必需字段'}), 400
    
    try:
        region_id = region_dao.create_region(template_id, name, int(x), int(y), int(width), int(height))
        return jsonify({'success': True, 'region_id': region_id})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/regions/<int:region_id>/edit', methods=['POST'])
def edit_region(region_id):
    """编辑定制区域"""
    data = request.get_json()
    
    name = data.get('name')
    x = data.get('x')
    y = data.get('y')
    width = data.get('width')
    height = data.get('height')
    
    if not all([name, x is not None, y is not None, width, height]):
        return jsonify({'error': '请填写所有必需字段'}), 400
    
    try:
        region_dao.update_region(region_id, name, int(x), int(y), int(width), int(height))
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/regions/<int:region_id>/delete', methods=['POST'])
def delete_region(region_id):
    """删除定制区域"""
    try:
        region_dao.delete_region(region_id)
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# =============================================================================
# 图片定制路由
# =============================================================================

@app.route('/customize')
def customize():
    """图片定制页面"""
    templates = template_dao.get_all_templates()
    projects = project_dao.get_all_projects()
    
    # 转换Row对象为字典
    templates_list = [dict(tmpl) for tmpl in templates] if templates else []
    projects_list = [dict(proj) for proj in projects] if projects else []
    
    return render_template('customize.html', templates=templates_list, projects=projects_list)

@app.route('/customize/new')
def new_customization():
    """新建定制项目"""
    templates = template_dao.get_all_templates()
    
    # 转换Row对象为字典
    templates_list = [dict(tmpl) for tmpl in templates] if templates else []
    
    return render_template('customize_editor.html', templates=templates_list)

@app.route('/customize/<int:project_id>')
def edit_customization(project_id):
    """编辑定制项目"""
    project = project_dao.get_project_by_id(project_id)
    if not project:
        flash('项目不存在', 'error')
        return redirect(url_for('customize'))
    
    template = template_dao.get_template_by_id(project['template_id'])
    regions = region_dao.get_regions_by_template(project['template_id'])
    templates = template_dao.get_all_templates()
    
    # 转换Row对象为字典
    project_dict = dict(project) if project else {}
    template_dict = dict(template) if template else {}
    regions_list = [dict(region) for region in regions] if regions else []
    templates_list = [dict(tmpl) for tmpl in templates] if templates else []
    
    return render_template('customize_editor.html', 
                         project=project_dict, 
                         template=template_dict, 
                         regions=regions_list,
                         templates=templates_list)

@app.route('/api/template/<int:template_id>/regions')
def get_template_regions(template_id):
    """获取底板的定制区域数据"""
    template = template_dao.get_template_by_id(template_id)
    if not template:
        return jsonify({'error': '底板不存在'}), 404
    
    regions = region_dao.get_regions_by_template(template_id)
    
    # 获取底板图层信息
    template_layers = []
    if template['image_path']:
        try:
            from photoshop_tiff_processor import PhotoshopTiffProcessor
            processor = PhotoshopTiffProcessor()
            
            image_path = template['image_path']
            if Path(image_path).is_absolute():
                template_image_path = Path(image_path)
            else:
                template_image_path = app.config['UPLOAD_FOLDER'] / image_path
            
            if template_image_path.exists():
                # 根据文件类型选择处理器
                if template_image_path.suffix.lower() == '.psd':
                    # PSD文件处理
                    from psd_processor import PSDProcessor
                    psd_processor = PSDProcessor()
                    template_layers = psd_processor.get_psd_layers_for_frontend(str(template_image_path))
                    print(f"检测到PSD文件，{len(template_layers)} 个图层")
                else:
                    # TIFF文件处理
                    template_layers = processor.extract_photoshop_layers(str(template_image_path))
                    print(f"检测到TIFF文件，{len(template_layers)} 个图层")
        except Exception as e:
            print(f"获取图层信息失败: {e}")
            # 回退到单图层
            template_layers = [{
                'name': '主图层',
                'type': 'pixel',
                'visible': True,
                'opacity': 255,
                'blend_mode': 'normal',
                'is_group': False,
                'width': template['width'],
                'height': template['height']
            }]
    
    return jsonify({
        'template': dict(template),
        'regions': [dict(region) for region in regions],
        'template_layers': template_layers
    })

@app.route('/upload_json', methods=['POST'])
def upload_json():
    """上传JSON配置文件"""
    if 'file' not in request.files:
        return jsonify({'error': '没有选择文件'}), 400
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': '没有选择文件'}), 400
    
    if file and allowed_file(file.filename, app.config['ALLOWED_JSON_EXTENSIONS']):
        try:
            # 读取JSON内容
            json_content = json.loads(file.read().decode('utf-8'))
            
            # 保存文件
            filename = secure_filename(file.filename)
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"{timestamp}_{filename}"
            file_path = app.config['UPLOAD_FOLDER'] / filename
            
            # 重新定位文件指针并保存
            file.seek(0)
            file.save(file_path)
            
            return jsonify({
                'success': True,
                'filename': filename,
                'data': json_content
            })
        except json.JSONDecodeError:
            return jsonify({'error': 'JSON文件格式错误'}), 400
        except Exception as e:
            return jsonify({'error': str(e)}), 500
    
    return jsonify({'error': '不支持的文件格式'}), 400

# =============================================================================
# 智能图片定位路由
# =============================================================================

@app.route('/intelligent')
def intelligent_positioning():
    """智能图片定位页面"""
    templates = template_dao.get_all_templates()
    templates_list = [dict(tmpl) for tmpl in templates] if templates else []
    return render_template('intelligent_positioning.html', templates=templates_list)

@app.route('/api/intelligent_analysis', methods=['POST'])
def intelligent_analysis():
    """智能分析API"""
    data = request.get_json()
    
    template_id = data.get('template_id')
    json_data = data.get('json_data')
    
    if not all([template_id, json_data]):
        return jsonify({'error': '缺少必要参数'}), 400
    
    try:
        # 获取模板信息
        template = template_dao.get_template_by_id(template_id)
        if not template:
            return jsonify({'error': '模板不存在'}), 404
        
        regions = region_dao.get_regions_by_template(template_id)
        regions_data = [dict(region) for region in regions] if regions else []
        
        # 创建智能定位系统
        from intelligent_garment_positioning import IntelligentGarmentPositioning
        positioning_system = IntelligentGarmentPositioning()
        
        # 执行智能分析
        result = positioning_system.create_intelligent_layout(
            template_id, json_data, regions_data
        )
        
        if result.get('error'):
            return jsonify({'error': result['error']}), 500
        
        return jsonify({
            'success': True,
            'result': result
        })
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/save_intelligent_project', methods=['POST'])
def save_intelligent_project():
    """保存智能定位项目"""
    data = request.get_json()
    
    project_name = data.get('project_name')
    template_id = data.get('template_id')
    analysis_result = data.get('analysis_result')
    uploaded_images = data.get('uploaded_images', {})
    customization_data = data.get('customization_data')
    
    if not all([project_name, template_id, analysis_result]):
        return jsonify({'error': '缺少必要参数'}), 400
    
    try:
        # 保存项目到数据库
        project_config = {
            'type': 'intelligent_positioning',
            'analysis_result': analysis_result,
            'uploaded_images_count': len(uploaded_images),
            'customization_data': customization_data
        }
        
        project_id = project_dao.create_project(
            name=project_name,
            template_id=template_id,
            json_config=json.dumps(project_config, ensure_ascii=False)
        )
        
        return jsonify({
            'success': True,
            'project_id': project_id,
            'message': f'智能项目“{project_name}”保存成功'
        })
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/apply_layer_adjustments', methods=['POST'])
def apply_layer_adjustments():
    """应用图层颜色调整和图片旋转"""
    data = request.get_json()
    
    template_id = data.get('template_id')
    layer_adjustments = data.get('layer_adjustments', {})
    image_rotations = data.get('image_rotations', {})
    
    if not template_id:
        return jsonify({'error': '缺少模板ID'}), 400
    
    try:
        # 获取模板信息
        template = template_dao.get_template_by_id(template_id)
        if not template:
            return jsonify({'error': '模板不存在'}), 404
        
        # 应用图层颜色调整
        from image_processor import ImageProcessor
        processor = ImageProcessor()
        
        # 创建临时调整后的底板
        adjusted_template_path = processor.apply_template_layer_adjustments(
            dict(template), layer_adjustments
        )
        
        return jsonify({
            'success': True,
            'adjusted_template_path': str(adjusted_template_path.name) if adjusted_template_path else None,
            'message': f'已应用 {len(layer_adjustments)} 个图层的颜色调整'
        })
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/export_intelligent_layout', methods=['POST'])
def export_intelligent_layout():
    """导出智能布局结果"""
    data = request.get_json()
    
    template_id = data.get('template_id')
    uploaded_images = data.get('uploaded_images', {})
    export_format = data.get('export_format', 'tif')
    preserve_layers = data.get('preserve_layers', True)
    custom_filename = data.get('custom_filename', '')  # 用户自定义文件名
    layer_adjustments = data.get('layer_adjustments', {})  # 图层颜色调整
    image_rotations = data.get('image_rotations', {})  # 图片旋转信息
    
    if not template_id or not uploaded_images:
        return jsonify({'error': '缺少必要参数'}), 400
    
    try:
        # 获取模板信息
        template = template_dao.get_template_by_id(template_id)
        regions = region_dao.get_regions_by_template(template_id)
        
        # 创建定制数据
        customization_data = {'regions': {}}
        
        for index, image_data in uploaded_images.items():
            # 保存base64图片到本地
            import base64
            header, encoded = image_data['dataUrl'].split(',', 1)
            image_bytes = base64.b64decode(encoded)
            
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            temp_filename = f"intelligent_upload_{index}_{timestamp}.png"
            temp_path = app.config['UPLOAD_FOLDER'] / temp_filename
            
            with open(temp_path, 'wb') as f:
                f.write(image_bytes)
            
            # 创建元素配置
            match = image_data['match']
            rotation_angle = image_rotations.get(index, 0)  # 获取旋转角度
            
            element_config = {
                'image_url': f'/uploads/{temp_filename}',
                'user_placement_data': {
                    'position': {
                        'x': match['optimal_position']['x'],
                        'y': match['optimal_position']['y']
                    },
                    'dimension': {
                        'width': match['optimal_position'].get('width', 300),
                        'height': match['optimal_position'].get('height', 300)
                    },
                    'scale': {'scale_x': 1.0, 'scale_y': 1.0},
                    'angle_of_rotation': rotation_angle
                }
            }
            
            region_index = str(match['optimal_position'].get('region_id', index))
            if region_index not in customization_data['regions']:
                customization_data['regions'][region_index] = {'elements': []}
            
            customization_data['regions'][region_index]['elements'].append(element_config)
        
        # 生成最终图片
        processor = ImageProcessor()
        result_path = processor.create_customized_image(
            template=dict(template),
            regions=[dict(region) for region in regions],
            customization_data=customization_data,
            export_format=export_format,
            preserve_layers=preserve_layers,
            custom_filename=custom_filename,  # 传递自定义文件名
            layer_adjustments=layer_adjustments  # 传递图层颜色调整
        )
        
        return jsonify({
            'success': True,
            'export_path': str(result_path.name),
            'download_url': url_for('download_export', filename=result_path.name),
            'message': f'智能布局导出成功（{len(uploaded_images)}个图片）'
        })
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/save_project', methods=['POST'])
def save_project():
    """保存定制项目"""
    data = request.get_json()
    
    project_id = data.get('project_id')
    name = data.get('name')
    template_id = data.get('template_id')
    json_config = data.get('json_config')
    
    if not all([name, template_id]):
        return jsonify({'error': '请填写项目名称和选择底板'}), 400
    
    try:
        if project_id:
            # 更新现有项目
            project_dao.update_project(project_id, name=name, json_config=json.dumps(json_config))
        else:
            # 创建新项目
            project_id = project_dao.create_project(name, template_id, json.dumps(json_config))
        
        return jsonify({'success': True, 'project_id': project_id})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/export_image', methods=['POST'])
def export_image():
    """导出定制后的图片"""
    data = request.get_json()
    
    template_id = data.get('template_id')
    customization_data = data.get('customization_data')
    export_format = data.get('export_format', 'png').lower()
    preserve_layers = data.get('preserve_layers', False)  # 新增参数
    custom_filename = data.get('custom_filename', '')  # 用户自定义文件名
    
    if not all([template_id, customization_data]):
        return jsonify({'error': '缺少必要参数'}), 400
    
    # 验证导出格式
    if export_format not in ['png', 'jpg', 'jpeg', 'tif', 'tiff', 'psd']:
        export_format = 'png'
    
    # 如果选择保留图层但格式不支持，给出警告
    if preserve_layers and export_format not in ['tif', 'tiff', 'psd']:
        print(f"警告：图层保留仅支持TIFF和PSD格式，当前格式: {export_format}")
        preserve_layers = False
    
    try:
        # 获取底板和区域信息
        template = template_dao.get_template_by_id(template_id)
        regions = region_dao.get_regions_by_template(template_id)
        
        # 使用图像处理器生成最终图片
        processor = ImageProcessor()
        result_path = processor.create_customized_image(
            template=dict(template),
            regions=[dict(region) for region in regions],
            customization_data=customization_data,
            export_format=export_format,
            preserve_layers=preserve_layers,  # 传递图层保留参数
            custom_filename=custom_filename  # 传递自定义文件名
        )
        
        # 根据是否保留图层返回不同的消息
        success_message = '图片导出成功'
        if preserve_layers and export_format in ['tif', 'tiff']:
            success_message += '（已保留图层信息）'
        elif export_format in ['tif', 'tiff']:
            success_message += '（图层已合并）'
        
        return jsonify({
            'success': True,
            'export_path': str(result_path.name),
            'download_url': url_for('download_export', filename=result_path.name),
            'message': success_message,
            'layers_preserved': preserve_layers and export_format in ['tif', 'tiff']
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/projects/<int:project_id>/delete', methods=['POST'])
def delete_project(project_id):
    """删除项目"""
    try:
        project_dao.delete_project(project_id)
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/exports')
def exports():
    """导出图片管理页面"""
    try:
        export_folder = Path(app.config['EXPORT_FOLDER'])
        export_files = []
        
        if export_folder.exists():
            for file_path in export_folder.iterdir():
                if file_path.is_file() and file_path.suffix.lower() in ['.png', '.jpg', '.jpeg', '.tif', '.tiff']:
                    stat = file_path.stat()
                    # 为TIF文件创建预览URL
                    preview_url = url_for('download_export', filename=file_path.name)
                    if file_path.suffix.lower() in ['.tif', '.tiff']:
                        preview_url = url_for('export_preview', filename=file_path.name)
                    
                    export_files.append({
                        'filename': file_path.name,
                        'size': stat.st_size,
                        'created_at': datetime.fromtimestamp(stat.st_ctime),
                        'modified_at': datetime.fromtimestamp(stat.st_mtime),
                        'format': file_path.suffix.upper().lstrip('.'),
                        'download_url': url_for('download_export', filename=file_path.name),
                        'preview_url': preview_url
                    })
        
        # 按创建时间倒序排列
        export_files.sort(key=lambda x: x['created_at'], reverse=True)
        
        return render_template('exports.html', export_files=export_files)
    except Exception as e:
        return render_template('exports.html', export_files=[], error=str(e))

@app.route('/exports/<filename>/delete', methods=['POST'])
def delete_export(filename):
    """删除导出文件"""
    try:
        file_path = Path(app.config['EXPORT_FOLDER']) / filename
        if file_path.exists() and file_path.is_file():
            file_path.unlink()
            return jsonify({'success': True})
        else:
            return jsonify({'error': '文件不存在'}), 404
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/downloads/<filename>')
def download_export(filename):
    """下载导出的文件"""
    return send_from_directory(app.config['EXPORT_FOLDER'], filename)

@app.route('/export_preview/<filename>')
def export_preview(filename):
    """生成导出文件的预览图片"""
    try:
        file_path = Path(app.config['EXPORT_FOLDER']) / filename
        if not file_path.exists():
            return jsonify({'error': '文件不存在'}), 404
        
        # 如果是TIF文件，转换为PNG预览
        if file_path.suffix.lower() in ['.tif', '.tiff']:
            from PIL import Image
            img = Image.open(file_path)
            
            # 创建缩略图
            img.thumbnail((400, 400), Image.Resampling.LANCZOS)
            
            # 转换为PNG
            if img.mode != 'RGB':
                if img.mode == 'RGBA':
                    # 创建白色背景
                    background = Image.new('RGB', img.size, (255, 255, 255))
                    background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                    img = background
                else:
                    img = img.convert('RGB')
            
            # 保存到内存
            from io import BytesIO
            img_io = BytesIO()
            img.save(img_io, 'PNG', optimize=True)
            img_io.seek(0)
            
            return Response(
                img_io.getvalue(),
                mimetype='image/png',
                headers={'Cache-Control': 'public, max-age=3600'}
            )
        else:
            # 非TIF文件直接返回
            return send_from_directory(app.config['EXPORT_FOLDER'], filename)
            
    except Exception as e:
        print(f"生成预览失败: {e}")
        return jsonify({'error': '生成预览失败'}), 500

@app.route('/uploads/<filename>')
def download_upload(filename):
    """访问上传的文件"""
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

@app.route('/template_image/<int:template_id>')
def get_template_image(template_id):
    """获取底板图片"""
    template = template_dao.get_template_by_id(template_id)
    if not template or not template['image_path']:
        print(f"模板{template_id}不存在或没有图片路径")
        return jsonify({'error': '图片不存在'}), 404
    
    try:
        from pathlib import Path
        image_path = template['image_path']
        print(f"尝试加载图片: {image_path}")
        
        # 判断是相对路径还是绝对路径
        if Path(image_path).is_absolute():
            # 绝对路径 - 直接读取本地文件
            file_path = Path(image_path)
        else:
            # 相对路径 - 在uploads目录中
            file_path = app.config['UPLOAD_FOLDER'] / image_path
        
        print(f"实际文件路径: {file_path}")
        print(f"文件是否存在: {file_path.exists()}")
        
        if not file_path.exists():
            print(f"文件不存在: {file_path}")
            return jsonify({'error': '文件不存在'}), 404
        
        # 对于PSD和TIF文件，转换为PNG格式
        if file_path.suffix.lower() == '.psd':
            print("检测到PSD文件，转换为PNG格式")
            try:
                from psd_tools import PSDImage
                from PIL import Image
                from io import BytesIO
                
                # 打开PSD文件并合成所有图层
                psd = PSDImage.open(file_path)
                img = psd.composite()
                
                # 转换为RGB模式
                if img.mode in ['RGBA', 'LA']:
                    rgb_img = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'RGBA':
                        rgb_img.paste(img, mask=img.split()[-1])
                    else:
                        rgb_img.paste(img)
                    img = rgb_img
                elif img.mode not in ['RGB', 'L']:
                    img = img.convert('RGB')
                
                # 如果图片太大，创建缩略图
                if img.width > 1200 or img.height > 1200:
                    print(f"PSD图片较大({img.width}x{img.height})，创建缩略图")
                    img.thumbnail((1200, 1200), Image.Resampling.LANCZOS)
                
                # 转换为PNG字节流
                img_io = BytesIO()
                img.save(img_io, 'PNG', optimize=True, quality=85)
                img_io.seek(0)
                
                print(f"PSD转PNG成功，尺寸: {img.width}x{img.height}")
                
                return Response(
                    img_io.getvalue(),
                    mimetype='image/png',
                    headers={
                        'Cache-Control': 'no-cache, no-store, must-revalidate',
                        'Content-Type': 'image/png'
                    }
                )
                
            except ImportError:
                return jsonify({'error': 'PSD文件需要安装psd-tools库'}), 500
            except Exception as e:
                print(f"PSD处理失败: {e}")
                return jsonify({'error': f'PSD文件处理失败: {str(e)}'}), 500
                
        elif file_path.suffix.lower() in ['.tif', '.tiff']:
            print("检测到TIF文件，转换为PNG格式")
            from PIL import Image
            from io import BytesIO
            
            with Image.open(file_path) as img:
                # 转换为RGB模式（如果需要）
                if img.mode in ['RGBA', 'LA']:
                    # 创建白色背景
                    rgb_img = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'RGBA':
                        rgb_img.paste(img, mask=img.split()[-1])
                    else:
                        rgb_img.paste(img)
                    img = rgb_img
                elif img.mode not in ['RGB', 'L']:
                    img = img.convert('RGB')
                
                # 如果图片太大，创建缩略图
                if img.width > 1200 or img.height > 1200:
                    print(f"图片较大({img.width}x{img.height})，创建缩略图")
                    img.thumbnail((1200, 1200), Image.Resampling.LANCZOS)
                
                # 转换为PNG字节流
                img_io = BytesIO()
                img.save(img_io, 'PNG', optimize=True, quality=85)
                img_io.seek(0)
                
                print(f"TIF转PNG成功，尺寸: {img.width}x{img.height}")
                
                return Response(
                    img_io.getvalue(),
                    mimetype='image/png',
                    headers={
                        'Cache-Control': 'public, max-age=3600',
                        'Content-Type': 'image/png'
                    }
                )
        else:
            # 其他格式直接返回
            print("直接返回图片文件")
            with open(file_path, 'rb') as f:
                image_data = f.read()
            
            # 确定MIME类型
            import mimetypes
            mime_type = mimetypes.guess_type(str(file_path))[0] or 'image/jpeg'
            
            return Response(
                image_data,
                mimetype=mime_type,
                headers={
                    'Cache-Control': 'public, max-age=3600'
                }
            )
        
    except Exception as e:
        print(f"读取底板图片失败: {e}")
        import traceback
        traceback.print_exc()
        
        # 返回一个错误占位符图片
        from PIL import Image, ImageDraw, ImageFont
        from io import BytesIO
        
        try:
            # 创建错误占位符
            img = Image.new('RGB', (400, 300), color='#f0f0f0')
            draw = ImageDraw.Draw(img)
            
            try:
                font = ImageFont.truetype("arial.ttf", 16)
            except:
                font = ImageFont.load_default()
            
            text = f"图片加载失败\n{str(e)[:50]}"
            bbox = draw.textbbox((0, 0), text, font=font)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]
            x = (400 - text_width) // 2
            y = (300 - text_height) // 2
            
            draw.text((x, y), text, fill='#666666', font=font)
            
            img_io = BytesIO()
            img.save(img_io, 'PNG')
            img_io.seek(0)
            
            return Response(
                img_io.getvalue(),
                mimetype='image/png'
            )
        except:
            return jsonify({'error': '图片处理失败'}), 500

@app.route('/proxy_image', methods=['GET', 'OPTIONS'])
def proxy_image():
    """代理外部图片以解决CORS问题"""
    # 处理CORS预检请求
    if request.method == 'OPTIONS':
        return Response(
            '',
            headers={
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Max-Age': '86400'
            }
        )
    
    image_url = request.args.get('url')
    if not image_url:
        return jsonify({'error': '缺少图片URL'}), 400
    
    print(f"代理图片请求: {image_url}")
    
    try:
        import requests
        import time
        from urllib3.util.retry import Retry
        from requests.adapters import HTTPAdapter
        
        # 创建带重试机制的会话
        session = requests.Session()
        retry_strategy = Retry(
            total=3,
            backoff_factor=1,
            status_forcelist=[429, 500, 502, 503, 504, 424],  # 包含424错误
            allowed_methods=["HEAD", "GET", "OPTIONS"]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        session.mount("http://", adapter)
        session.mount("https://", adapter)
        
        # 改进的请求头，模拟真实浏览器行为
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'Accept': 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
            'Accept-Encoding': 'gzip, deflate, br',
            'Cache-Control': 'no-cache',
            'Pragma': 'no-cache',
            'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
            'Sec-Ch-Ua-Mobile': '?0',
            'Sec-Ch-Ua-Platform': '"Windows"',
            'Sec-Fetch-Dest': 'image',
            'Sec-Fetch-Mode': 'no-cors',
            'Sec-Fetch-Site': 'cross-site',
            'DNT': '1',
        }
        
        # 如果URL来自特定域名，设置适当的Referer
        if 'temu.com' in image_url:
            headers['Referer'] = 'https://www.temu.com/'
        elif 'alibaba.com' in image_url or 'alicdn.com' in image_url:
            headers['Referer'] = 'https://www.alibaba.com/'
        elif 'taobao.com' in image_url or 'tbcdn.cn' in image_url:
            headers['Referer'] = 'https://www.taobao.com/'
        else:
            # 通用referer
            headers['Referer'] = 'https://www.google.com/'
        
        # 发送请求
        response = session.get(
            image_url, 
            headers=headers, 
            timeout=30,
            allow_redirects=True,
            stream=True  # 使用流式传输以处理大文件
        )
        
        print(f"图片请求响应: {response.status_code} - {response.reason}")
        print(f"响应头: {dict(response.headers)}")
        
        # 检查HTTP状态码
        if response.status_code == 200:
            # 检查内容类型
            content_type = response.headers.get('content-type', '').lower()
            if not content_type.startswith('image/'):
                print(f"警告: 响应的内容类型不是图片: {content_type}")
                # 如果内容类型不是图片，仍然尝试处理，有些服务器可能返回错误的MIME类型
            
            # 读取图片内容
            content = response.content
            print(f"图片下载成功，大小: {len(content)} bytes")
            
            if len(content) == 0:
                raise Exception("图片内容为空")
            
            # 验证图片格式
            try:
                from PIL import Image as PILImage
                with BytesIO(content) as img_buffer:
                    test_img = PILImage.open(img_buffer)
                    test_img.verify()  # 验证图片完整性
                print("图片格式验证通过")
            except Exception as e:
                print(f"图片格式验证失败: {e}")
                # 即使验证失败也继续，有些图片可能验证失败但仍然可用
            
            # 返回图片数据
            return Response(
                content,
                mimetype=response.headers.get('content-type', 'image/jpeg'),
                headers={
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                    'Access-Control-Allow-Headers': 'Content-Type',
                    'Cache-Control': 'public, max-age=3600',
                    'Content-Length': str(len(content))
                }
            )
        elif response.status_code == 424:
            # 特殊处理424错误 - 依赖关系失败
            print(f"遇到424错误，可能是请求依赖问题，尝试简化请求")
            
            # 使用更简单的请求头重试
            simple_headers = {
                'User-Agent': 'Mozilla/5.0 (compatible; ImageProxy/1.0)',
                'Accept': '*/*',
            }
            
            simple_response = requests.get(
                image_url, 
                headers=simple_headers, 
                timeout=15,
                allow_redirects=True
            )
            
            if simple_response.status_code == 200:
                content = simple_response.content
                print(f"简化请求成功，图片大小: {len(content)} bytes")
                return Response(
                    content,
                    mimetype=simple_response.headers.get('content-type', 'image/jpeg'),
                    headers={
                        'Access-Control-Allow-Origin': '*',
                        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                        'Access-Control-Allow-Headers': 'Content-Type',
                        'Cache-Control': 'public, max-age=3600'
                    }
                )
            else:
                raise Exception(f"简化请求也失败: HTTP {simple_response.status_code}")
        else:
            print(f"图片请求失败: {response.status_code} {response.reason}")
            raise Exception(f"HTTP {response.status_code}: {response.reason}")
            
    except requests.exceptions.RequestException as e:
        print(f"请求异常: {type(e).__name__}: {e}")
        error_msg = f"请求失败: {type(e).__name__}"
        if "424" in str(e):
            error_msg = "依赖关系失败(424)"
        elif "timeout" in str(e).lower():
            error_msg = "请求超时"
        elif "connection" in str(e).lower():
            error_msg = "连接失败"
    except Exception as e:
        print(f"代理图片失败: {e}")
        error_msg = f"处理失败: {str(e)[:30]}"
        
    # 返回错误占位符图片
    try:
        img = Image.new('RGB', (300, 300), color='#f0f0f0')
        draw = ImageDraw.Draw(img)
        
        try:
            font = ImageFont.truetype("arial.ttf", 16)
        except:
            font = ImageFont.load_default()
        
        # 绘制错误信息
        lines = [
            "图片加载失败",
            error_msg,
            "使用占位符"
        ]
        
        y_start = 100
        for i, line in enumerate(lines):
            bbox = draw.textbbox((0, 0), line, font=font)
            text_width = bbox[2] - bbox[0]
            x = (300 - text_width) // 2
            y = y_start + i * 30
            draw.text((x, y), line, fill='#666666', font=font)
        
        # 添加一个小图标
        draw.rectangle([130, 50, 170, 90], outline='#cccccc', width=2)
        draw.line([140, 60, 160, 80], fill='#cccccc', width=2)
        draw.line([140, 80, 160, 60], fill='#cccccc', width=2)
        
        # 返回占位符图片
        img_io = BytesIO()
        img.save(img_io, 'PNG', optimize=True)
        img_io.seek(0)
        
        print(f"返回占位符图片，大小: {len(img_io.getvalue())} bytes")
        
        return Response(
            img_io.getvalue(),
            mimetype='image/png',
            headers={
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Cache-Control': 'public, max-age=60'
            }
        )
    except Exception as fallback_error:
        print(f"创建占位符图片失败: {fallback_error}")
        # 最后的回退，返回简单的错误响应
        return jsonify({'error': '图片加载失败'}), 503

# =============================================================================
# 错误处理
# =============================================================================

@app.errorhandler(404)
def not_found(error):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_error(error):
    return render_template('500.html'), 500

@app.errorhandler(413)
def too_large(error):
    return jsonify({'error': '文件太大，请选择小于50MB的文件'}), 413

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
